#include "Harvest.h"
#include "State.h"
#include "const.h"
#include "macro.h"

//-----------------------------------------------------------------------------
template <typename T>
struct CanMove
{
    CanMove(T* state) : state(state) {}

    bool operator () (const Ant& ant, const Task& task) const
    {
        return state->canMove(ant, task);
    }

    T* state;
};

//-----------------------------------------------------------------------------
template <typename T>
struct CanFollow
{
    CanFollow(T* state) : state(state) {}

    bool operator () (const Ant& ant, const Task& task) const
    {
        return state->canFollow(ant, task) && !state->state->grid[task.row][task.col].isHill;
    }

    T* state;
};
//-----------------------------------------------------------------------------
void Harvest::operator()(const Target::AntVector::value_type& ant)
{
    WeightTask task;
    WeightTask previousTask;

    //OUT_PRINT "Find task for " << ant << "..." << std::endl;
    // find new task (nearest food/hill/etc)
    if (getTask(ant, task, ENUMERATE_OCCUPED))
    {
        bool occuped = taskOccuped(state->tasks, task.first, previousTask);
        assign(ant, task);

        if (occuped)
        {
//            OUT_PRINT "Replace task " << previousTask.first << "->" << task.first << " to " << ant << "->" << task.first << std::endl;
            (*this)(previousTask.first);
        }
    }
    else
    {
        state->freeAnts.push_back(ant);
    }
}

// return true if found best task
bool Harvest::getTask(const Ant& ant, WeightTask& task, bool enumerateOccuped)
{
    if ( !FindNearestTarget(ant, state->food, state->GetMapResolution(), task, CanMove<Harvest>(this)))
    //if ( !FindNearestTarget(ant, state->myAnts, state->GetMapResolution(), task, CanFollow<Harvest>(this)))
        return false;

    return true;
}

int Harvest::distanceFast(const Location &loc1, const Location &loc2) const
{
//    return abs(loc1.row - loc2.row + rows) % rows + abs(loc1.col - loc2.col + cols) % cols;
    return ::distanceFast(loc1, loc2, state->GetMapResolution());
}

bool Harvest::canMove(const Location& from, const Location& to) const
{
    return state->canMove(from,to);
}

bool Harvest::canFollow(const Location& from, const Location& to) const
{
    bool result = (DIRECTION_UNKNOWN != state->GetDirection(from,to));

    return result;
}

bool Harvest::tryMove(const Ant& ant, const Task& task)
{
    int direction = state->GetDirection(ant,task);
    //OUT_PRINT ant << " direction: "<< direction << std::endl;
    if ( DIRECTION_UNKNOWN != direction )
    {
        std::cout << "o " << ant.row << " " << ant.col << " " << CDIRECTIONS[direction] << std::endl;
        Location nLoc = state->getLocation(ant, direction);
        //target.doMoveAnt(loc,nLoc);
        state->grid[nLoc.row][nLoc.col].ant = state->grid[ant.row][ant.col].ant;
        state->grid[ant.row][ant.col].ant = -1;
    }
    return DIRECTION_UNKNOWN != direction;
}
